const puppeteer = require('puppeteer')
const axios = require('axios')
const cherrio = require('cheerio')
const fs = require('fs')
const tesseract = require('node-tesseract')
const codechek = require('../codecheck')
// let holdon = false

const { Database, Model } = require('mongorito')

const db = new Database('localhost/aihuishou')

class Mobile extends Model {}
class Setting extends Model {}

async function initDataBase(params) {
  await db.connect()
  db.register(Mobile)
  db.register(Setting)
}

const host = 'http://www.aishouji.com'
/** 模型接口 */
const models_url = 'http://www.aihuishou.com/util/GetSearchHot?pageSize=1000'

let browser
// FormData
const FormData = {
  auctionProductId: 23423,
  priceUnits:
    '5033;2022;2014;4459;2072;2100;2126;2120;2115;2067;2107;2134;3168;2108;2026;;;;;2045;2102;;2104;2129;;;;;2112;2808'
}

async function sleep(timeout = 3000) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(true)
    }, timeout)
  })
}

async function holdonYZM(name, interval) {
  return new Promise(async (resolve, reject) => {
    let holdon = await Setting.findOne({ name: 'holdon' })
    if (holdon.get('value')) {
      if (!interval) {
        console.log('holdonYZM', name, '等待', holdon.get('value'))
      }
      setTimeout(async () => {
        return resolve(holdonYZM(name, true))
      }, 1000)
    } else {
      resolve(true)
    }
  })
}

function getBrands(params = '') {
  if (params.includes('红米')) return '红米'
  return null
}

function unionCombine(arr1, arr2) {
  let result = []
  let i = 0
  do {
    for (let ii = 0; ii < arr2.length; ii++) {
      const item = [arr2[ii]]
      if (arr1[i] instanceof Array) {
        item.unshift(...arr1[i])
      }
      result.push(item)
    }
    i++
  } while (i < arr1.length)

  return result
}

function ArrayCombine(arr1) {
  let result = []
  for (let i = 0; i < arr1.length; i++) {
    for (let ii = 0; ii < arr1.length; ii++) {
      if (ii + i + 1 > arr1.length) continue
      const item = [...arr1.slice(ii, i + ii + 1)]
      result.push(item)
    }
  }
  return result
}

// 入口
async function getModelsData() {
  let data = []
  let brands = []

  const { data: brandsHtml } = await axios({
    url: 'http://www.aihuishou.com/shouji',
    method: 'get'
  })

  const $ = cherrio.load(brandsHtml)

  $('#body > div.product-class-main > div.main-right > ul > li > a').each((index, elem) => {
    const $elem = $(elem)
    brands.push($elem.text().trim())
  })

  const { data: models } = await axios({ url: 'http://www.aihuishou.com/util/GetSearchHot?pageSize=10000' })
  data = models.data.map(item => {
    let brand = brands.find(b => item.name.includes(b)) || getBrands(item.name)
    if (brand == null) {
      brand = item.name
      console.log(item.name)
    }
    return {
      id: item.id,
      model: item.name,
      brand
    }
  })

  fs.writeFileSync('data.json', JSON.stringify(data))
}

async function tryPraseCode(path) {
  return new Promise((resolve, reject) => {
    tesseract.process(path, function(err, text) {
      if (err) {
        reject(err)
      } else {
        resolve(text)
      }
    })
  })
}
async function getProducts(page, { id, model, brand }) {
  return new Promise(async (resolve, reject) => {
    await page.goto(`http://www.aihuishou.com/product/${id}.html`)
    // 等待加载完
    await page.waitFor(1000)
    // 统计所有分类
    const properties = await page.evaluate(() => {
      let list = document.querySelectorAll('#group-property > div.right > div.select-property > dl')
      let properties = []
      list.forEach(item => {
        let key
        let values
        if (item.children.length > 1) {
          key = item.children[0].innerText
          values = item.children[1].children[0].children
        } else {
          key = '功能性问题'
          values = item.children[0].children[0].children
        }
        if (key === '存储容量 如何查看存储容量 ') {
          key = key.replace(' 如何查看存储容量 ', '')
        }
        if (key === '小型号 如何查看小型号 ') {
          key = key.replace(' 如何查看小型号 ', '')
        }
        if (key === '型号 如何查看型号 ') {
          key = key.replace(' 如何查看型号 ', '')
        }
        let result = []
        for (let i = 0; i < values.length; i++) {
          const element = values[i]
          result.push({
            key,
            name: element.innerText.trim(),
            value: element.getAttribute('data-id'),
            defaultValue: element.getAttribute('data-default')
          })
        }
        properties.push(result)
      })
      return properties
    })
    // const functionProps = ArrayCombine(properties[properties.length - 1])

    let allGroup = []
    properties.slice(0, -1).forEach(item => {
      allGroup = unionCombine(allGroup, item)
    })
    console.log('success', `${id} ${brand} ${model} :`, allGroup.length)
    for (let i = 0; i < allGroup.length; i++) {
      const item = allGroup[i]
      const post = new Mobile({ productId: id, model, brand, props: item, propsLength: item.length })
      await post.save()
    }
    resolve(true)
  })
}

async function createPrice(page, mobile, name) {
  return new Promise(async (resolve, reject) => {
    try {
      let productId = mobile.get('productId')
      let props = mobile.get('props')
      await page.goto(`http://www.aihuishou.com/product/${productId}.html`)
      // 等待加载完
      await page.waitFor(1000)
      for (let ii = 0; ii < props.length; ii++) {
        // console.log(props[ii].value)
        await page.evaluate(() => {
          document.querySelector('#body > div.unlock-tips').style.display = 'none'
        })

        await page.waitFor(150)
        await page.mouse.move(0, 0)
        await page.waitForSelector(
          `#group-property > div.right > div.select-property > dl > dd > ul > li[data-id="${props[ii].value}"]`
        )

        await page.waitFor(150)
        await page.click(
          `#group-property > div.right > div.select-property > dl > dd > ul > li[data-id="${props[ii].value}"]`
        )
      }

      await page.waitFor(100)
      await holdonYZM(name)
      await page.click('#submit')
      const hasYzmCode = await hasYzm(page)
      if (hasYzmCode) {
        console.log(name, '设置holdon为true')
        const currHoldon = await Setting.findOne({ name: 'holdon' })
        currHoldon.set('value', true)
        await currHoldon.save()
        await tryYzm(page, name)
        console.log('hand up yzm finish,', name)
      } else {
        await page.waitFor(1000)
      }

      // console.log('hand up yzm finish3')
      // await $price.screenshot({ path: pricePath })
      // const result = await tryPraseCode(pricePath)

      const result = await page.evaluate(() => {
        const price = document.querySelector('#quoter-section').getAttribute('data-price')
        return price
      })
      // console.log(result)
      await page.waitFor(500)
      await page.goBack()
      resolve(result)
    } catch (error) {
      await initDataBase()
      const currHoldon = await Setting.findOne({ name: 'holdon' })
      currHoldon.set('value', false)
      await currHoldon.save()
      return resolve(createPrice(page, mobile, name))
    }
  })
}

async function hasYzm(page) {
  return new Promise(async (resolve, reject) => {
    try {
      await page.waitForSelector('#inquiry-captcha > input[type="text"]', { timeout: 1000, visible: true })
      return resolve(true)
    } catch (error) {
      return resolve(false)
    }
  })
}

async function unHasYzm(page) {
  return new Promise(async (resolve, reject) => {
    try {
      await page.waitForSelector(
        '#quoter-section > div > div.quotre-content.clearfix > div.quoter-price > div.price-wrap > div > span.number',
        { timeout: 1000, visible: true }
      )
      return resolve(true)
    } catch (error) {
      return resolve(false)
    }
  })
}

async function tryYzm(page, name) {
  return new Promise(async (resolve, reject) => {
    try {
      for (let i = 0; i < 4; i++) {
        await page.click('#inquiry-captcha > img')
      }
      const yzmCode = await YZM(page, 'tryYzm', name)
      await page.evaluate(() => {
        document.querySelector('#inquiry-captcha > input[type="text"]').value = ''
      })
      await page.type('#inquiry-captcha > input[type="text"]', yzmCode)
      await page.click('#submit')

      await page.waitFor(1000)

      const unHasYzmCode = await unHasYzm(page)
      console.log('unHasYzmCode', unHasYzmCode)
      if (!unHasYzmCode) {
        return resolve(tryYzm(name, page))
      } else {
        const currHoldon = await Setting.findOne({ name: 'holdon' })
        currHoldon.set('value', false)
        console.log(name, 'holdon', currHoldon.get('value'))
        await currHoldon.save()
        return resolve(true)
      }
    } catch (error) {
      // console.log('error')
      return resolve(tryYzm(name, page))
    }
  })
}

async function YZM(page, target, name) {
  return new Promise(async (resolve, reject) => {
    // console.log(name, 'fn YZM by', target)
    await page.waitFor(300)
    const $yzm = await page.$('#inquiry-captcha > img')
    await $yzm.screenshot({ path: './caches/yzm.jpeg' })
    let yzmCode = await codechek.parseYZM('./caches/yzm.jpeg')
    if (yzmCode) {
      resolve(yzmCode)
    } else {
      await page.waitFor(300)
      await page.click('#inquiry-captcha > img')
      yzmCode = await YZM(page, 'itself', name)
      resolve(yzmCode)
    }
  })
}

async function tryssss(name, pageNumber) {
  return new Promise(async (resolve, reject) => {
    try {
      browser = await puppeteer.launch({ headless: true })
      const page = await browser.newPage()
      page.on('dialog', async dialog => {
        await dialog.dismiss()
      })
      const watchDog = page.waitForFunction('window.innerWidth < 1000')
      page.setViewport({ width: 1280, height: 700 })
      await watchDog

      const total = await Mobile.count()
      const totalPage = total / 100
      console.log('总条数', total)
      for (let pageIndex = 1; pageIndex <= totalPage; pageIndex++) {
        console.log('还剩', totalPage - pageIndex)
        const mobiles = await Mobile.limit(100)
          .skip((pageIndex + pageNumber) * 100)
          .find({ price: null })
        console.time(pageIndex)
        for (let i = 0; i < mobiles.length; i++) {
          // await page.waitFor(1 * 1000)
          const mobile = mobiles[i]
          const price = await createPrice(page, mobile, name)
          console.log(`${name}：第${pageIndex}页 ,第${i + 1}条：${price}`)
          mobile.set('price', price)
          await mobile.save()
        }
        console.timeEnd(pageIndex)
      }
      resolve(true)
    } catch (error) {
      reject(error)
    }
  })
}

// run()
// createPrice()
async function run(params) {
  await initDataBase()
  const currHoldon = await Setting.findOne({ name: 'holdon' })
  currHoldon.set('value', false)
  await currHoldon.save()
  try {
    tryssss('爬虫1', 1)
    await sleep(2000)
    tryssss('爬虫3', 12)
  } catch (error) {
    console.log('tryssss')
    tryssss()
  }
}
run()
// tryPraseCode('./caches/code.jpeg')
